package cn.topevery.garden.dal.logic;

import cn.topevery.garden.dal.dao.ClockInDao;
import cn.topevery.garden.dal.util.GeomHelper;
import cn.topevery.garden.entity.dto.ClockInDTO;
import cn.topevery.garden.entity.fetch.ClockFetch;
import cn.topevery.garden.entity.po.ClockIn;
import cn.topevery.garden.entity.po.PersonAttendance;
import cn.topevery.garden.entity.po.Section;
import cn.topevery.garden.entity.po.WorkPlan;
import cn.topevery.garden.entity.query.ClockInQuery;
import cn.topevery.garden.entity.query.PersonAttendanceQuery;
import cn.topevery.garden.entity.vo.ClockInVO;
import cn.topevery.garden.entity.vo.PersonAttendanceVO;
import cn.topevery.garden.entity.vo.PersonVO;
import cn.topevery.garden.framework.base.BaseLogic;
import com.github.dozermapper.core.Mapper;
import hw.topevery.basis.entity.po.SysDept;
import hw.topevery.basis.entity.po.SysUser;
import hw.topevery.framework.GeometryHelper;
import hw.topevery.framework.db.base.BaseEntityDao;
import hw.topevery.framework.db.entity.DataPager;
import hw.topevery.framework.entity.KeyValue;
import hw.topevery.framework.enums.GeometryTypeEnum;
import hw.topevery.framework.web.JsonResult;
import org.apache.commons.lang3.StringUtils;
import org.locationtech.jts.geom.Geometry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.validation.constraints.NotEmpty;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * @author code-generate
 * @date 2022-01-05
 */
@Service
public class ClockInLogic extends BaseLogic<ClockIn> {
    @Autowired
    ClockInDao clockInDao;

    @Override
    public BaseEntityDao<ClockIn, Integer> getDao() {
        return clockInDao;
    }

    @Autowired
    PersonAttendanceLogic personAttendanceLogic;

    @Autowired
    private Mapper mapper;

    @Autowired
    private PersonLogic personLogic;

    @Autowired
    private SectionLogic sectionLogic;

    @Autowired
    private WorkPlanLogic workPlanLogic;

    /**
     * 获取列表
     *
     * @param query
     */
    public DataPager<ClockInVO> listPage(ClockInQuery query) {
        return clockInDao.listPage(query);
    }

    /**
     * 根据自增id批量删除
     *
     * @param ids
     */
    public void deleteBatchById(String userId, Integer[] ids) {
        clockInDao.delete(userId, ids);
    }

    /**
     * 根据自增id保存或者更新
     *
     * @param clockIn 实体
     */
    public void saveOrUpdate(String userId, ClockIn clockIn) {
        clockInDao.saveOrUpdate(userId, clockIn);
        // 添加考勤记录
        PersonAttendanceQuery query = new PersonAttendanceQuery();
        query.setPageIndex(1);
        query.setPageSize(10);
        query.setUserId(clockIn.getUserId());
        DateTimeFormatter dtf2 = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String format = dtf2.format(clockIn.getDate());
        query.setDate(format);
        DataPager<PersonAttendanceVO> personAttendanceVODataPager = personAttendanceLogic.listPage(query);
        PersonAttendanceVO personAttendanceVO = new PersonAttendanceVO();
        if (personAttendanceVODataPager.total == 0) {
            // 新增
            personAttendanceVO.setEntityId(UUID.randomUUID().toString());
            personAttendanceVO.setDate(LocalDate.parse(format, dtf2));
            personAttendanceVO.setUserName(clockIn.getName());
            personAttendanceVO.setUserId(clockIn.getUserId());
        } else {
            //修改
            personAttendanceVO = personAttendanceVODataPager.records.get(0);
        }

        if (clockIn.getType().equals(1)) {
            personAttendanceVO.setSignIn(clockIn.getDate());
            personAttendanceVO.setSignInOvertimes(clockIn.getOvertimes());
        }
        if (clockIn.getType().equals(2)) {
            personAttendanceVO.setSignOut(clockIn.getDate());
            personAttendanceVO.setSignOutOvertimes(clockIn.getOvertimes());
        }
        personAttendanceLogic.saveOrUpdate(userId, mapper.map(personAttendanceVO, PersonAttendance.class));
    }

    /**
     * 根据自定义列值来获取对象
     */
    public ClockIn getEntityByColumn(String key, String value) {
        return clockInDao.getEntityByColumn(key, value);
    }

    public DataPager<ClockIn> getList(ClockFetch para) {
        return clockInDao.getList(para);
    }

    public List<ClockIn> getClockInList(ClockInQuery query) {
        return clockInDao.getClockInList(query);
    }

    public JsonResult<?> userIsInSectionRange(@NotEmpty SysUser user, @NotEmpty Double lng, @NotEmpty Double lat, @NotEmpty Double offset) {
        PersonVO personVO = personLogic.getByUserId(user.userId);
        if (personVO == null || personVO.getSectionId() == null || personVO.getShiftId() == null) {
            return JsonResult.error("当前人员所属标段或班次还未绑定");
        }
        Section section = sectionLogic.getEntity(personVO.getSectionId());
        return JsonResult.ok(this.isInSectionRange(section.getGeomWgs(), lng, lat, offset));
    }

    public Boolean isInSectionRange(@NotEmpty Geometry geomWgs, @NotEmpty Double lng, @NotEmpty Double lat, @NotEmpty Double offset) {
        Geometry sectionMkt = GeometryHelper.buildMercatorGeometry(GeometryHelper.getGeometryPoint(geomWgs), GeometryTypeEnum.PLANE);
        GeometryHelper.MapPoint curPoint = GeometryHelper.xyToMercator(lng, lat);
        return GeomHelper.inGeom(sectionMkt, curPoint.x, curPoint.y, offset);
    }

    public JsonResult<?> clockIn(SysUser user, SysDept dept, ClockInDTO dto) {
        //判断当前人员是否在其所属标段内
        PersonVO personVO = personLogic.getByUserId(user.userId);
        if (personVO == null || personVO.getSectionId() == null || personVO.getShiftId() == null) {
            return JsonResult.error("当前人员所属标段或班次还未绑定");
        }
        Section section = sectionLogic.getEntity(personVO.getSectionId());
        if (section.getGeomWgs() == null) {
            return JsonResult.error("当前人员所属标段还未规划地理范围");
        }
        boolean isInSection = this.isInSectionRange(section.getGeomWgs(), dto.getLng(), dto.getLat(), 100D);
        if (!isInSection) {
            return JsonResult.error("当前人员位置不在所属标段范围内");
        }
        dto.setIsRange(true);
        //判断当前人员是否在上班时间
        WorkPlan workPlan = workPlanLogic.getEntity(personVO.getShiftId());
        LocalTime now = LocalTime.now();
        if (now.isBefore(workPlan.beginTime)) {//上班打卡
            //查询当天是否已打卡
            ClockFetch clockFetch = new ClockFetch();
            clockFetch.setMinDate(LocalDate.now());
            DataPager<ClockIn> list = clockInDao.getList(clockFetch);
            if (!CollectionUtils.isEmpty(list.records)) {
                //判定为早退
                dto.setIsValid(3);
                dto.setType(2);
                //计算早退时长
                long earlyLeaveSeconds = Duration.between(workPlan.beginTime, workPlan.endTime).getSeconds();
                dto.setOvertimes(earlyLeaveSeconds);
            } else {
                //正常打上班卡
                dto.setIsValid(1);
                dto.setOvertimes(0L);
                dto.setType(1);
            }
        } else {
            //查询当天是否打了上班卡
            ClockFetch clockFetch = new ClockFetch();
            clockFetch.setMinDate(LocalDate.now());
            clockFetch.setType(1);
            DataPager<ClockIn> list = clockInDao.getList(clockFetch);
            if (now.isAfter(workPlan.beginTime) && now.isBefore(workPlan.endTime)) {
                if (!CollectionUtils.isEmpty(list.records)) {
                    //判定为早退
                    dto.setIsValid(3);
                    dto.setType(2);
                    //计算早退时长
                    long earlyLeaveSeconds = Duration.between(now, workPlan.endTime).getSeconds();
                    dto.setOvertimes(earlyLeaveSeconds);
                } else {
                    //判定为迟到
                    dto.setIsValid(2);
                    dto.setType(1);
                    //计算迟到时长
                    long lateSeconds = Duration.between(workPlan.beginTime, now).getSeconds();
                    dto.setOvertimes(lateSeconds);
                }
            } else {//下班打卡
                dto.setIsValid(1);
                dto.setType(2);
            }
        }
        dto.setIsUse(1);
        if (StringUtils.isBlank(dto.getEntityId())) {
            dto.setEntityId(UUID.randomUUID().toString());
        }
        dto.setDate(now.atDate(LocalDate.now()));
        dto.setUserId(user.userId);
        dto.setName(user.userName);
        dto.setCompanyName(dept.deptName);
        dto.setSectionId(personVO.getSectionId().toString());
        dto.setSectionName(personVO.getSectionName());
        //更新打卡状态，将重复多余的打卡记录设置为不使用，即使当天当前时间之前的所有下班卡失效
        clockInDao.updateClockRecord(user.id.toString());
        this.insert(user.id.toString(), mapper.map(dto, ClockIn.class));
        return JsonResult.ok("打卡成功！");
    }

    public List<ClockIn> clockInfoToday(String userId) {
        return clockInDao.getListEntityByColumns(new ArrayList<KeyValue>() {{
            add(new KeyValue("c_db_status", 0));
            add(new KeyValue("DATE(c_date)", LocalDate.now()));
            add(new KeyValue("c_is_use", 1));
            add(new KeyValue("c_user_id", userId));
        }});
    }
}
